---
title: Mojo language basics
sidebar_position: 1
sidebar_label: Overview
description: An overview of the Mojo language.
---

This page provides an overview of the Mojo language.

If you know Python, then a lot of Mojo code will look familiar. However, Mojo
incorporates features like static type checking, memory safety, next-generation
compiler technologies, and more. As such, Mojo also has a lot in common with
languages like C++ and Rust.

If you prefer to learn by doing, follow the [Get started with
Mojo](/mojo/manual/get-started) tutorial.

On this page, we'll introduce the essential Mojo syntax, so you can start
coding quickly and understand other Mojo code you encounter. Subsequent
sections in the Mojo Manual dive deeper into these topics, and links are
provided below as appropriate.

Let's get started! 🔥

:::note

Mojo is a young language and there are many [features still
missing](/mojo/roadmap). As such, Mojo is currently **not** meant for
beginners. Even this basics section assumes some programming experience.
However, throughout the Mojo Manual, we try not to assume experience with any
particular language.

:::

## Hello world

Here's the traditional "Hello world" program in Mojo:

```mojo
def main():
    print("Hello, world!")
```

Every Mojo program must include a function named `main()` as the entry point.
We'll talk more about functions soon, but for now it's enough to know that
you can write `def main():` followed by an indented function body.

The `print()` statement does what you'd expect, printing its arguments to
the standard output.

## Variables

In Mojo, you can declare a variable by simply assigning a value to
a new named variable:

```mojo
def main():
    x = 10
    y = x * x
    print(y)
```

You can also _explicitly_ declare variables with the `var` keyword:

```mojo
var x = 10
```

When declaring a variable with `var`, you can also declare a variable type, with
or without an assignment:


```mojo
def main():
    var x: Int = 10
    var sum: Int
    sum = x + x
```

Both implicitly declared and explicitly declared variables are statically typed:
that is, the type is set at compile time, and doesn't change at runtime.
If you don't specify a type, Mojo uses the type of the first value assigned to
the variable.

```mojo
x = 10
x = "Foo" # Error: Cannot convert "StringLiteral" value to "Int"
```

For more details, see the page about
[variables](/mojo/manual/variables).

## Blocks and statements

Code blocks such as functions, conditions, and loops are defined
with a colon followed by indented lines. For example:

```mojo
def loop():
    for x in range(5):
        if x % 2 == 0:
            print(x)
```

You can use any number of spaces or tabs for your indentation (we prefer 4
spaces).

All code statements in Mojo end with a newline. However, statements can span
multiple lines if you indent the following lines. For example, this long string
spans two lines:

```mojo
def print_line():
    long_text = "This is a long line of text that is a lot easier to read if"
                " it is broken up across two lines instead of one long line."
    print(long_text)
```

And you can chain function calls across lines:

```mojo
def print_hello():
    text = ",".join("Hello", " world!")
    print(text)
```

For more information on loops and conditional statements, see
[Control flow](/mojo/manual/control-flow).

## Functions

You can define a Mojo function using either the `def` or `fn` keyword. For
example, the following uses the `def` keyword to define a function named
`greet` that requires a single `String` argument and returns a `String`:

```mojo
def greet(name: String) -> String:
    return "Hello, " + name + "!"
```

Where `def` and `fn` differ is error handling and argument mutability defaults.
Refer to the [Functions](/mojo/manual/functions) page for more details on
defining and calling functions.

## Code comments

You can create a one-line comment using the hash `#` symbol:

```mojo
# This is a comment. The Mojo compiler ignores this line.
```

Comments may also follow some code:

```mojo
var message = "Hello, World!" # This is also a valid comment
```

API documentation comments are enclosed in triple quotes. For example:

```mojo
fn print(x: String):
    """Prints a string.

    Args:
        x: The string to print.
    """
    ...
```

Documenting your code with these kinds of comments (known as "docstrings")
is a topic we've yet to fully specify, but you can generate an API reference
from docstrings using the [`mojo doc` command](/mojo/cli/doc).

:::note

Technically, docstrings aren't _comments_, they're a special use of Mojo's
syntax for multi-line string literals. For details, see
[String literals](/mojo/manual/types#string-literals) in the page on
[Types](/mojo/manual/types).

:::

## Structs

You can build high-level abstractions for types (or "objects") as a `struct`.

A `struct` in Mojo is similar to a `class` in Python: they both support
methods, fields, operator overloading, decorators for metaprogramming, and so
on. However, Mojo structs are completely static—they are bound at compile-time,
so they do not allow dynamic dispatch or any runtime changes to the structure.
(Mojo will also support Python-style classes in the future.)

For example, here's a basic struct:

```mojo
struct MyPair(Copyable):
    var first: Int
    var second: Int

    fn __init__(out self, first: Int, second: Int):
        self.first = first
        self.second = second

    fn __copyinit__(out self, existing: Self):
        self.first = existing.first
        self.second = existing.second

    def dump(self):
        print(self.first, self.second)
```

And here's how you can use it:

```mojo
def use_mypair():
    var mine = MyPair(2, 4)
    mine.dump()
```

Note that some functions are declared with `fn` function, while the `dump()`
function is declared with `def`. In general, you can use either form in a
struct.

The `MyPair` struct contains two special methods, `__init__()`, the constructor,
and `__copyinit__()`, the copy constructor. _Lifecycle methods_ like this
control how a struct is created, copied, moved, and destroyed.

For most simple types, you don't need to write the lifecycle methods. You can
use the `@fieldwise_init` decorator to generate the boilerplate field-wise
initializer for you, and Mojo will synthesize copy and move constructors if you
ask for them with trait conformance. So the
`MyPair` struct can be simplified to this:

```mojo
@fieldwise_init
struct MyPair(Copyable):
    var first: Int
    var second: Int

    def dump(self):
        print(self.first, self.second)
```

For more details, see the page about
[structs](/mojo/manual/structs).

### Traits

A trait is like a template of characteristics for a struct. If you want to
create a struct with the characteristics defined in a trait, you must implement
each characteristic (such as each method). Each characteristic in a trait is a
"requirement" for the struct, and when your struct implements all of the
requirements, it's said to "conform" to the trait.

Using traits allows you to write generic functions that can accept any type
that conforms to a trait, rather than accept only specific types.

For example, here's how you can create a trait:

```mojo
trait SomeTrait:
    fn required_method(self, x: Int): ...
```

The three dots following the method signature are Mojo syntax indicating that
the method is not implemented.

Here's a struct that conforms to `SomeTrait`:

```mojo
@fieldwise_init
struct SomeStruct(SomeTrait):
    fn required_method(self, x: Int):
        print("hello traits", x)
```

Then, here's a function that uses the trait as an argument type (instead of the
struct type):

```mojo
fn fun_with_traits[T: SomeTrait](x: T):
    x.required_method(42)

fn use_trait_function():
    var thing = SomeStruct()
    fun_with_traits(thing)
```

You'll see traits used in a lot of APIs provided by Mojo's standard library. For
example, Mojo's collection types like `List` and `Dict` can store any type that
conforms to the `Copyable` trait. You can specify the type when
you create a collection:

```mojo
my_list = List[Float64]()
```

:::note

You're probably wondering about the square brackets on `fun_with_traits()`.
These aren't function *arguments* (which go in parentheses); these are function
*parameters*, which we'll explain next.

:::

Without traits, the `x` argument in `fun_with_traits()` would have to declare a
specific type that implements `required_method()`, such as `SomeStruct`
(but then the function would accept only that type). With traits, the function
can accept any type for `x` as long as it conforms to (it "implements")
`SomeTrait`. Thus, `fun_with_traits()` is known as a "generic function" because
it accepts a *generalized* type instead of a specific type.

For more details, see the page about [traits](/mojo/manual/traits).

## Parameterization

In Mojo, a parameter is a compile-time variable that becomes a runtime
constant, and it's declared in square brackets on a function or struct.
Parameters allow for compile-time metaprogramming, which means you can generate
or modify code at compile time.

Many other languages use "parameter" and "argument" interchangeably, so be
aware that when we say things like "parameter" and "parametric function," we're
talking about these compile-time parameters. Whereas, a function "argument" is
a runtime value that's declared in parentheses.

Parameterization is a complex topic that's covered in much more detail in the
[Metaprogramming](/mojo/manual/parameters/) section, but we want to break the
ice just a little bit here. To get you started, let's look at a parametric
function:

```mojo
def repeat[count: Int](msg: String):
    @parameter # evaluate the following for loop at compile time
    for i in range(count):
        print(msg)
```

This function has one parameter of type `Int` and one argument of type
`String`. To call the function, you need to specify both the parameter and the
argument:

```mojo
def call_repeat():
    repeat[3]("Hello")
    # Prints "Hello" 3 times
```

By specifying `count` as a parameter, the Mojo compiler is able to optimize the
function because this value is guaranteed to not change at runtime. And the
`@parameter` decorator in the code tells the compiler to evaluate the `for` loop
at compile time, not runtime.

The compiler effectively generates a unique version of the `repeat()` function
that repeats the message only 3 times. This makes the code more performant
because there's less to compute at runtime.

Similarly, you can define a struct with parameters, which effectively allows
you to define variants of that type at compile-time, depending on the parameter
values.

For more detail on parameters, see the section on
[Metaprogramming](/mojo/manual/parameters/).

## Python integration

Mojo supports the ability to import Python modules as-is, so you can leverage existing Python code right away.

For example, here's how you can import and use NumPy:

```mojo
from python import Python

def main():
    var np = Python.import_module("numpy")
    var ar = np.arange(15).reshape(3, 5)
    print(ar)
    print(ar.shape)
```

You must have the Python module (such as `numpy`) installed in the environment
where you're using Mojo.

For more details, see the page on
[Python integration](/mojo/manual/python/).

## Next steps

Hopefully this page has given you enough information to start experimenting with
Mojo, but this is only touching the surface of what's available in Mojo.

If you're in the mood to read more, continue through each page of this
Mojo Manual—the next page from here is [Functions](/mojo/manual/functions).

Otherwise, here are some other resources to check out:

* See [Get started with Mojo](/mojo/manual/get-started) for a hands-on
  tutorial that will get you up and running with Mojo.

* If you want to experiment with some code, clone [our GitHub
  repo](https://github.com/modular/modular/) to try our code examples:

  ```sh
  git clone https://github.com/modular/modular.git
  ```

  ```sh
  cd max/examples/mojo
  ```

* To see all the available Mojo APIs, check out the [Mojo standard library
  reference](/mojo/lib).
